home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / games / dcg408up.zip / EXAMPLE / CONTROL.SCR < prev    next >
Text File  |  1997-03-03  |  65KB  |  2,166 lines

  1. !
  2. ! CONTROL.SCR
  3. !
  4. ! This script manages some independent functions of the game system.  The
  5. ! script is called by the game driver at certain points during game play,
  6. ! and the entry points are numeric (@0, @1, @2..) instead of the usual entry
  7. ! points (@TALK, @GET, ..).
  8. !
  9. ! QUICK SUMMARY OF ENTRY POINTS:
  10. !
  11. ! :@0 - Time Control.         Executed once every minute of game time.
  12. !                             (See 'MOVES_PER_MINUTE' parameter)
  13. !
  14. ! :@1 - PLAYER MOVES          Invoked ONCE for EACH player during a FIGHT
  15. !
  16. ! :@2 - MONSTER MOVES         Invoked ONCE ONLY to move ALL monsters (at
  17. !                             once) during a FIGHT.
  18. !
  19. ! :@3 - Keyboard/Mouse Event. MAIN EVENT HANDLER. Called for every key
  20. !                             pressed or mouse button clicked during
  21. !                             normal game play.
  22. !
  23. ! :@4 - POSITION MONSTER      Called ONCE ONLY when STARTING a fight.
  24. !                             The array of NPCs (foreach NPC do..) is
  25. !                             the set of expanded monsters from the 
  26. !                             original monster being fought. They all
  27. !                             have the same X/Y position and need to 
  28. !                             be "spread out" for fighting
  29. !
  30. ! :@5 - NPC MOVES             Called ONCE after every @3 call, this
  31. !                             entry point allows you to animate the 
  32. !                             NPCs in the game. In general, it's a bad
  33. !                             idea to try to animate too many NPCs. It's
  34. !                             main purpose at this time is to allow for
  35. !                             HOSTILE npc animation under script control.
  36. !
  37. ! LAST MOD.  BY              DESCRITPION
  38. ! 10-15-95   D. Hernandez    First release for DCGAMES Version 4.0
  39. ! 11-15-95   D. Hernandez    Added hidden/locked landscape door handling
  40. !
  41. !
  42. !---------------------------------------------------------------------------!
  43. :@0 ! Entry Point @0 : Time Control Script                                  !
  44. !---------------------------------------------------------------------------!
  45. !
  46. ! This script will start execution at this label once per 'minute' during
  47. ! regular play.  The variable GROUP.MOVES contains the total number of
  48. ! moves the party has made since the begining of the game.  A minute is
  49. ! defined by the current value of the variable 'MovesPerMinute'
  50. !
  51. ! Time is controled by seting the following variables from any script:
  52. !
  53. !   Variable             Default  Description
  54. !   -------------------  -------  --------------------------------
  55. !   MovesPerMinute             2  # of moves per game 'minute'
  56. !   MinutesInAnHour           60  # of minutes in an game 'hour'
  57. !   HoursInADay               24  # of hour in a game 'day'
  58. !   DaysInAMonth              30  # of days in a game 'month'
  59. !   MonthsInAYear             12  # of months in a game 'year'
  60. !   
  61. ! The CURRENT time is obtained (and modified) by setting the following
  62. ! variables:
  63. !
  64. !   year                 Current Year   (Range -32767 to 32767)
  65. !   month                Current Month  (Range 0 to MonthsInAYear - 1)
  66. !   day                  Current Day    (Range 0 to DaysInAMonth  - 1)
  67. !   hour                 Current Hour   (Range 0 to HoursInADay   - 1)
  68. !   minute               Current Minute (Range 0 to MinutesInADay - 1)
  69. !
  70.  
  71. ! Update the clock, one more minute has passed !
  72.  
  73.   gosub CLOCK_TICK;
  74.   if minute = 0 gosub CLOCK_PRINT;
  75.  
  76. ! No perform some time dependent actions
  77. ! First, save our original status just in case we need it later..
  78.   L255 = group.current; ! Save current party spokesperson   !
  79.   L254 = FALSE;         ! Have NOT created a random monster !
  80.  
  81. ! THINGS TO DO EVERY MINUTE  
  82.   if group.energy > 0 then
  83.     dec( group.energy );
  84.     ! In the desert, during the day, you consume energy twice as fast
  85.     if world.density(group.x,group.y) = DESERT and group.vehicle.count = 0 then
  86.       if hour > sunrise and hour < sunset then
  87.         dec( group.energy ); 
  88.       endif;
  89.     endif;
  90.     if L2 = SWAMP and group.vehicle.count = 0 then 
  91.       if random(5) = 0 then ! one out of 5 !
  92.         L255 = group.current;
  93.         foreach player do
  94.           if not player.poisoned then
  95.             player.poisoned = (random(3) = 0); ! one out of 3 !
  96.             if player.poisoned then
  97.               writeln( player.name, " got poisoned by swamp gas!" );
  98.             endif;
  99.           endif;
  100.         endfor;
  101.         group.current = L255; ! Restore the current spokesperson !
  102.       endif;
  103.     endif;
  104.   endif;
  105.   
  106. ! THINGS TO DO ONCE AN HOUR
  107. if minute = 0 then 
  108.   ! Create a random monster 1 out of every 5 times (approx) !
  109.   if random(5) = 0 then
  110.     if world.type = OUTDOORS or world.type = DUNGEON or world.type = HAUNTED then
  111.       gosub NEWMONSTER;
  112.     endif;
  113.   endif;
  114.  
  115.   ! Check to see if you have food.. !
  116.   if group.food <= group.size then
  117.     if group.food = 0 then
  118.       writeln( "You have no food.." );
  119.     else
  120.       writeln( "You are running out of food.." );
  121.     endif;
  122.   endif;
  123. endif;
  124.  
  125. ! Every quarter of an hour !
  126. L25 = max(MinutesInAnHour / 4 + 1,2);
  127. if minute % L25 = 0 then
  128.   ! Group must rest within 2 hours or start suffering damage !
  129.   if group.energy < MinutesInAnHour * 2 then 
  130.     if group.energy > 0 then
  131.       writeln( "You must rest soon.." );
  132.     else
  133.       writeln( "You are exhausted.." );
  134.     endif;
  135.   endif;
  136.   ! Check for poison, hunger and exhaustion !
  137.   foreach player do
  138.     if player.hp > 0 then
  139.       if player.poisoned then
  140.         s0 = "poisoning";
  141.         gosub HITPLAYER;
  142.       elsif player.energy = 0 and group.food = 0 then
  143.         s0 = "hunger";
  144.         gosub HITPLAYER;
  145.       elsif group.energy <= 0 then
  146.         s0 = "exhaustion";
  147.         gosub HITPLAYER;
  148.       endif;
  149.     endif;
  150.   endfor;
  151. endif;
  152.  
  153. !
  154. ! The following controls healing and recovery of power.  You can
  155. ! change the rate of healing by using a different value, but remember
  156. ! that the power heal value (8 below) should be a MULTIPLE of the
  157. ! first number (4) or it will not work.
  158. !
  159. if minute % 4 = 0 and group.energy > 0 then
  160.   foreach player do
  161.     if group.food or player.energy then
  162.       gosub HEAL_HP;
  163.       ! Every 8 (twice as slow) restore power
  164.       if minute % 8 = 0 then
  165.         gosub HEAL_PWR;
  166.       endif;
  167.     endif;
  168.   endfor;
  169. endif;
  170.  
  171. ! Go back with same selected spokesperson.. !
  172. group.current = L255;
  173. CONTINUE;
  174.  
  175. !---------------------------------------------------------------------------!
  176. :@1 ! PLAYER MOVES DURING A FIGHT
  177. !---------------------------------------------------------------------------!
  178. !
  179.   frame(player.x,player.y,SYS_FRAME);
  180.   write( player.name, " - " );
  181.   if player.hp < 2 then
  182.     if player.hp = 1 then writeln( "is unconscious!" );
  183.                      else writeln( "is dead!" ); 
  184.     endif;
  185.   elsif player.paralyzed then 
  186.     writeln( "is paralyzed!" );
  187.   elsif player.scared then
  188.     writeln( "is scared!" );
  189.   else
  190.     stats(player);
  191.     keypress = GET_ACTION;
  192.     frame(player.x,player.y,-SYS_FRAME);
  193.     goto :@3;
  194.   endif;
  195.   frame(player.x,player.y,-SYS_FRAME);
  196.   STOP;
  197.  
  198. !---------------------------------------------------------------------------!
  199. :@2 ! Move NPCs during a fight
  200. !---------------------------------------------------------------------------!
  201.   runscript( "FIGHTING", 1 );
  202.   stop;
  203.  
  204. !---------------------------------------------------------------------------!
  205. :@4 ! Position NPCs before a fight
  206. !---------------------------------------------------------------------------!
  207.   runscript( "FIGHTING", 0 );
  208.   stop;
  209.  
  210. !---------------------------------------------------------------------------!
  211. :@5 ! Animate NPCs (called after every call to @3) Except during a fight
  212. !---------------------------------------------------------------------------!
  213.   foreach visible npc do
  214.     if npc.type = HOSTILE then
  215.       ! Every 2nd move, if the NPC can see the player, they follow !
  216.       if group.moves % 2 = 0 and los( npc, group ) then 
  217.         L3 = group.x - npc.x;
  218.         L4 = group.y - npc.y;
  219.         if abs(L3) > npc.weapon.range or   ! Are we within the NPC's 
  220.            abs(L4) > npc.weapon.range then ! .. range?
  221.           L3 = sgn(L3); L0 = npc.x + L3;   ! NO, move npc towards the
  222.           L4 = sgn(L4); L1 = npc.y + L4;   ! .. player (one step only)
  223.           L2 = 0;                          ! set NPC moving Flag
  224.           L22 = npc.index;
  225.           gosub CHK_A_MOVE;                ! Call movement routine
  226.           if npc.index <> L22 then
  227.             npc.index = L22;
  228.           endif;
  229.           if NOT L2 then ! Can't move, try to move around the obstacle !
  230.             L3 = group.x - npc.x;
  231.             L4 = group.y - npc.y;
  232.             if L3 > L4 then ! 
  233.               L3 = sgn(L3); L0 = npc.x + L3;   ! Move one step in this...
  234.               L4 = 0;       L1 = npc.y;        ! .. direction...
  235.             else
  236.               L3 = 0;       L0 = npc.x;        ! Move one step in this...
  237.               L4 = sgn(L4); L1 = npc.y + L4;   ! .. direction...
  238.             endif;
  239.             L2 = 0;                            ! NPC moving again..
  240.             L22 = npc.index;
  241.             gosub CHK_A_MOVE;                ! Call movement routine
  242.             if npc.index <> L22 then
  243.               npc.index = L22;
  244.             endif;
  245.           endif;
  246.           if L2 then ! Move IT !
  247.             npc.x = L0;
  248.             npc.y = L1;
  249.           endif;
  250.         else
  251.           voice( "ALERT", 1000 );
  252.           writeln( "The ", npc.name, " attacks!" );
  253.           FIGHT;
  254.         endif;
  255.       endif; ! los() !
  256.     else   ! not-hostile !
  257.       if npc.block <> npc.block2 then
  258.         L0 = npc.block;
  259.         npc.block = npc.block2;
  260.         npc.block2 = L0;
  261.       else
  262.       !  OPTIONAL: If DCPEOPLE.VHx has TWO consecutive tiles per character
  263.       !  if npc.block % 2 = 0 then
  264.       !    inc( npc.block );
  265.       !  else
  266.       !    dec( npc.block );
  267.       !  endif;
  268.       endif;
  269.     endif;
  270.   endfor; ! visibile npcs !
  271.   if player.block <> player.block2 then
  272.     L0 = player.block;
  273.     player.block = player.block2;
  274.     player.block2 = L0;
  275.   else
  276.   !  if player.block % 2 = 0 then
  277.   !    inc( player.block );
  278.   !  else
  279.   !    dec( player.block );
  280.   !  endif;
  281.   endif;
  282.   stop;
  283.  
  284. !---------------------------------------------------------------------------!
  285. :@3 ! Keyboard Map Entry Point : Process a key press
  286. !---------------------------------------------------------------------------!
  287.  
  288. !
  289. ! THE FOLLOWING TABLE IS A SHORT LIST OF THE VALUES ASSOCIATED WITH EACH
  290. ! KEY. NOTE THAT SPECIAL KEYS HAVE BEEN MAPPED TO DISTINCT NUMBERS TO 
  291. ! AVOID USING THE WIERD PC KEY VALUES.
  292.  
  293. ! CTRL +A to Z    =   1 to  26
  294. ! ESCape key      =  27
  295. ! space           =  32
  296. ! 0-9             =  48 to  57
  297. ! A-Z             =  65 to  90 
  298. ! a-z             =  65 to  90 (i.e. NO LOWERCASE)
  299. ! F1 - F10        = 131 to 140
  300. ! Shift+F1 - F10  = 141 to 150
  301. ! Ctrl +F1 - F10  = 151 to 160
  302. ! ALT  +F1 - F10  = 161 to 170
  303. ! ALT  +1 to 10   = 171 to 180
  304. ! ALT  +A to Z    = 201 to 226
  305. !
  306. ! KEY PAD VALUES (arrow keys!):
  307. ! HOME            = 190        ! CTRL + HOME     = 187
  308. ! END             = 191        ! CTRL + END      = 186
  309. ! UP              = 192        ! CTRL + UP       = 230
  310. ! DOWN            = 193        ! CTRL + DOWN     = 231
  311. ! LEFT            = 194        ! CTRL + LEFT     = 184
  312. ! RIGHT           = 195        ! CTRL + RIGHT    = 185
  313. ! PGUP            = 196        ! CTRL + PGUP     = 189
  314. ! PGDN            = 197        ! CTRL + PGDN     = 188 
  315. ! INS             = 198
  316. ! DEL             = 199
  317. !
  318. ! When you use the mouse to click on something, the variable BUTTON
  319. ! contains which button you clicked (1=Left, 2=Right, 3=Middle), and
  320. ! the rest of the information is obtained as follos:
  321. !
  322. ! VALUE OF KEYPRESS Value of POINTX      Value of POINTY
  323. ! ----------------- ------------------   ------------------
  324. ! VIEW_CLICK  235   World X coordinate   World Y coordinate
  325. ! MENU_CLICK  236   Menu Offset          Menu Choice (0 to n)
  326. ! ICON_CLICK  237   0-7 icon position    0-n block # in DCSYSTEM.VH1
  327. ! STAT_CLICK  238   6 (group was shown)  0-n (group member clicked)
  328. ! CHAR_CLICK  239   0-n (current player) Clicked Item (in LIST)
  329. !                                        0 = nothing particular
  330. !                                        1 = weapon
  331. !                                        2 = shield
  332. !                                        3 = armor 
  333. !                                        4 = staff 
  334. !                                        5 = ring  
  335. !                                        6 = amulet
  336. ! BODY_CLICK  240   0-n (current player) Clicked Item
  337. !                                        0 = nothing particular
  338. !                                        1 = Hand One (weapon)
  339. !                                        2 = Hand Two (Shield/Staff)
  340. !                                        3 = Torso    (Armor)
  341. !                                        4 = Waist    (Belt)
  342. !                                        5 = Legs     (Leggings/pants)
  343. !                                        6 = Feet     (shoes)
  344. !                                        7 = Head     (hat/helmet)
  345. !                                        8 = Neck     (necklace/amulet)
  346. !                                        9 = Finger One (ring)
  347. !                                       10 = Finger Two (ring)
  348. ! PACK_CLICK  241   0-n (current player) 0-15 (Item # in backpack)
  349. ! MNAV_CLICK  242   0-5 mnav button      0-n block # in DCSYSTEM.VHx
  350. !
  351.   if KEYPRESS = 27 then
  352.     if fighting then
  353.       writeln( "Trying to escape.." );
  354.       fight( STOP );
  355.       ! You could call 'runscript( "FIGHTING", 2 )' if
  356.       ! You wanted too. Or even 'runscript( "FIGHTING", 6 )' for
  357.       ! all I care, if you wanted to have an @6 entry point for
  358.       ! handling fights.
  359.       STOP;
  360.     endif;
  361.   endif;
  362.   if KEYPRESS >= 65 and KEYPRESS <= 90 then
  363.     on KEYPRESS - 65 goto 
  364.       LETTER_A, LETTER_B, LETTER_C, LETTER_D, LETTER_E,
  365.       LETTER_F, LETTER_G, LETTER_H, LETTER_I, LETTER_J,
  366.       LETTER_K, LETTER_L, LETTER_M, LETTER_N, LETTER_O,
  367.       LETTER_P, LETTER_Q, LETTER_R, LETTER_S, LETTER_T,
  368.       LETTER_U, LETTER_V, LETTER_W, LETTER_X, LETTER_Y, LETTER_Z;
  369.   endif;
  370.   if KEYPRESS >= 48 and KEYPRESS <= 57 then
  371.     on KEYPRESS - 48 goto
  372.       DIGIT_0, DIGIT_1, DIGIT_2, DIGIT_3, DIGIT_4,
  373.       DIGIT_5, DIGIT_6, DIGIT_7, DIGIT_8, DIGIT_9;
  374.   endif;
  375.   if KEYPRESS = 32 goto SPACE;
  376.   ! KEYPAD ARROWS !
  377.   if KEYPRESS >= 190 and KEYPRESS <= 197 then
  378.     on KEYPRESS - 190 goto
  379.      MOVE_UL, MOVE_DL, MOVE_UP, MOVE_DN, MOVE_LF, MOVE_RT, MOVE_UR, MOVE_DR;
  380.   endif;
  381.   if KEYPRESS >= 201 and KEYPRESS <= 226 then
  382.     ! <ALT> + letter
  383.     if KEYPRESS = 222 goto ALT_V; ! Set the VOLUME !
  384.     CONTINUE;
  385.   endif;
  386.   if KEYPRESS >= 235 and KEYPRESS <= 242 then
  387.     on KEYPRESS - 235 goto
  388.        VIEW_CLICK, MENU_CLICK, ICON_CLICK, STAT_CLICK, 
  389.        CHAR_CLICK, BODY_CLICK, PACK_CLICK, MNAV_CLICK;
  390.   endif;
  391.   ! F1 - F10        = 131 to 140
  392.   if keypress >= 131 and keypress <= 140 then
  393.     on keypress - 131 goto FKEY1,FKEY2,FKEY3,FKEY4,FKEY5,FKEY6,FKEY7,FKEY8,FKEY9,FKEY10;
  394.   endif;
  395.  
  396.   ! Not handled by the script. The driver takes the default action !
  397.   CONTINUE;
  398.  
  399. :DIGIT_0
  400.   paint( SMALL );
  401.   STATS( group ); ! Display GROUP statistics !
  402.   STOP;
  403.  
  404. :DIGIT_1 :DIGIT_2 :DIGIT_3 :DIGIT_4 :DIGIT_5 :DIGIT_6
  405.   GROUP.CURRENT = KEYPRESS - 49; ! Use 0 to 5 instead of 1 to 6  !
  406.   STATS( GROUP.CURRENT );        ! Display INDIVIDUAL statistics !
  407.   STOP;
  408.  
  409. :DIGIT_7
  410.   stats( PREV );
  411.   STOP;
  412.  
  413. :DIGIT_8
  414.   stats( NEXT );
  415.   STOP;
  416.  
  417. :DIGIT_9
  418.   STOP;
  419.  
  420. :LETTER_A
  421.   write( "Attack: " );
  422.   L3 = locate;
  423.   if failure goto NOTHING;
  424.   ! Attack a character !
  425.   if npc.count and npc.x = pointx and npc.y = pointy then
  426.     writeln( npc.class );
  427.     if fighting then
  428.       goto ATTACK_NPC; ! if we ARE fighting, go do it.. !
  429.     else
  430.       if npc.type <> HOSTILE then
  431.         writeln( "Find some bad guys to fight!" );
  432.         STOP;
  433.       endif;
  434.     endif;
  435.     FIGHT; ! START FIGHT MODE. SCRIPT EXECUTION ENDS HERE !
  436.   elsif object.count then
  437.     if object.type = CHEST then
  438.       if object.locktype then
  439.         writeln( "Instead of fighting it, try 'UNLOCK'!" );
  440.       else
  441.         writeln( "It's not even locked, why fight it?" );
  442.       endif;
  443.     else
  444.       writeln( "Why would you want to fight the ", object.name );
  445.     endif;
  446.   endif;
  447.   STOP;
  448.  
  449. :LETTER_B
  450.   stats( player.body );
  451.   STOP;
  452.  
  453. !------------------------------------------------------------------------!
  454. :LETTER_C  ! CAMP OUT !
  455. !
  456. ! First, all temporary magical effects are eliminated by reducing any 
  457. ! attribute that exceeds the maximum value for the same attribute.
  458. !
  459. ! Armor, Shields, Rings and Amulets re-apply their effect (if any).
  460. !
  461. ! The group rests for a third of a day, in one hour increments.  For
  462. ! each hour rested, the group gains 4 hours of 'wake-up' energy.  This
  463. ! means the group should be able to go one and a third days without 
  464. ! sleep.
  465. !
  466. ! Random monsters may appear, but not too often.
  467. !
  468.   if fighting then
  469.     writeln( "This is not a good time to rest.." );
  470.     stop;
  471.   endif;
  472.   frame( group.x, group.y, 10 ); ! ZZZZ.... !
  473.   write( "Resting" );
  474.   voice( "snore", 1000 );
  475.   L255 = group.current; ! Save current party spokesperson   !
  476.   L254 = FALSE;         ! Have NOT created a random monster !
  477.   foreach player do
  478.     if player.hp > 0 then
  479.       gosub NEW_LEVEL; ! Figure out if character went up one level !
  480.       write(".");
  481.       ! First, get rid of temporary magical increases in attributes !
  482.       player.str = min(player.str,player.mstr);
  483.       player.aim = min(player.aim,player.maim);
  484.       player.dex = min(player.dex,player.mdex);
  485.       player.spd = min(player.spd,player.mspd);
  486.       player.pwr = min(player.pwr,player.mpwr);
  487.       player.hp  = min(player.hp, player.mhp);
  488.       player.iq  = min(player.iq, player.miq);
  489.       player.ac  = min(player.ac, player.mac);
  490.       if player.armor.count or player.shield.count then
  491.         if player.armor.cursed or player.shield.cursed then
  492.           player.ac = 0;
  493.         else
  494.           inc( player.ac, player.armor.ac + player.shield.ac );
  495.         endif;
  496.       endif;
  497.       if player.ring.count and player.ring.charges then
  498.         curritem = player.ring;
  499.         gosub M1_INVOKE;
  500.       endif;
  501.       if player.amulet.count and player.amulet.charges then
  502.         curritem = player.amulet;
  503.         gosub M1_INVOKE;
  504.       endif;
  505.     endif; ! Dead !
  506.   endfor; ! foreach player !
  507.  
  508.   ! # of hours to rest is one third of a day !
  509.   for L253 = 1 to HoursInADay / 3 + 1 do 
  510.     write(".");
  511.     ! Each hour of sleep gives 4 hours of energy !
  512.     if group.energy + MinutesInAnHour * 4 > 32767 then
  513.       group.energy = 32767;
  514.     else
  515.       inc( group.energy, MinutesInAnHour * 4 );
  516.     endif;
  517.     for L252 = 0 to MinutesInAnHour / 2 do
  518.       gosub CLOCK_TICK;
  519.       gosub CLOCK_TICK;
  520.       foreach player do
  521.        if group.food or player.energy then
  522.           gosub HEAL_HP;
  523.           if L252 % 2 then
  524.             gosub HEAL_PWR;
  525.           endif;
  526.         endif;
  527.       endfor;
  528.     endfor;
  529.     ! Check to see if random monsters appear !
  530.     if world.type = OUTDOORS or world.type = DUNGEON or world.type = HAUNTED then
  531.       if random(17) = 0 then
  532.         gosub NEWMONSTER;
  533.         if L254 then
  534.           frame( group.x, group.y, -1 ); ! Restore !
  535.           writeln( "You wake up under attack.." );
  536.           FIGHT;       ! Wake up and fight.. !
  537.         endif;
  538.       endif;
  539.     endif;
  540.   endfor;
  541.   group.current = L255; ! Go back to original spokes person !
  542.   frame( group.x, group.y, -1 ); ! Restore !
  543.   voice( "CHIMES", 1000 );
  544.   gosub CLOCK_PRINT;
  545.   STOP;
  546.  
  547. :LETTER_D
  548.   L0 = split;
  549.   stats( player.bp ); ! Show player's backpack !
  550.   paint(SMALL);       ! Now.. (in case it was small) !
  551.   write( "Drop " );
  552.   L1 = getaction;
  553.   if not L0 then paint(LARGE); endif;
  554.   if L1 = 241 then
  555.     if point_y >= 0 then
  556.       setbp( player, pointy );
  557.       if player.bp.count then
  558.         curritem = player.bp;
  559.         runscript( curritem.script, "CURRITEM", DROP );
  560.       endif;
  561.     endif;
  562.   endif;
  563. ! OLD SCRIPT ...
  564. !  L0 = select$n( player );
  565. !  if L0 >= 0 then
  566. !    writeln( player.bp.name );
  567. !    runscript( player.bp.script, "CURRITEM", DROP );
  568. !  endif;
  569.   writeln( "nothing.." );
  570.   STOP;
  571.  
  572. :LETTER_E
  573.   if group.vehicle.count then ! Must be on foot !
  574.     writeln( "You must be on foot to enter/exit worlds.." );
  575.     STOP;
  576.   endif;
  577.   if group.x <> 0 or group.y <> 0 then
  578.     for L0 = 0 to 31 do
  579.       if world.doorx(L0) = group.x and world.doory(L0) = group.y then
  580.         world.door = L0; ! Use this door !
  581.         writeln( "Please wait..." );
  582.         runscript( WORLD, "WORLDDEF", EXIT );
  583.         ! Should not return !
  584.       endif;
  585.     endfor;
  586.   endif;
  587.   writeln( "There is no door here.." );
  588.   STOP;
  589.  
  590. :LETTER_F
  591.   STOP;
  592.  
  593. :LETTER_G
  594.   ! Get !
  595.   if player.hp > 1 then
  596.     write( "Get " );
  597.     L0 = locate( object ); ! Find OBJECT only, no people !
  598.     if success then 
  599.       writeln( object.type );
  600.       if L0 < 2 then
  601.         runscript( object.script, "OBJECT", GET );
  602.         ! Does NOT return !
  603.       else
  604.         writeln( "You can't reach the ", object.type );
  605.       endif;
  606.     else
  607.       goto NOTHING;
  608.     endif;
  609.   else
  610.     write( player.name, " can't get anything.." );
  611.   endif;
  612.   STOP;
  613.  
  614. :LETTER_H  
  615.   STOP;
  616.  
  617. :LETTER_I
  618.   stats( player.bp ); ! Display Inventory, was -> display$n( player ); !
  619.   paint( SMALL );
  620.   STOP;
  621.  
  622. :LETTER_J
  623.   STOP;
  624.  
  625. :LETTER_K
  626.   STOP;
  627.  
  628. :LETTER_L
  629.   write( "Look at " );
  630.   L0 = locate; ! Find ANYTHING !
  631.   if success then 
  632.     if npc.count and npc.x = pointx and npc.y = pointy then ! Found an NPC !
  633.       writeln( npc.type );
  634.       runscript( npc.script, "OBJECT", LOOK );
  635.     endif;
  636.     writeln( object.type );
  637.     runscript( object.script, "OBJECT", LOOK );
  638.   endif;
  639.   if world.density(pointx,pointy) = LOCKED_DOOR then
  640.     writeln( "locked door." );
  641.     writeln( "You see a locked door." );
  642.     stop;
  643.   endif;
  644.   if world.density(pointx,pointy) = HIDDEN_DOOR then
  645.     writeln( "wall." );
  646.     if abs(pointx - player.x) > 2 or abs(pointy - player.y) > 2 then
  647.       writeln( "You must get closer to the wall." );
  648.     else
  649.       world.block(pointx,pointy) = world.block(pointx,pointy) - 1;
  650.       writeln( "You found a hidden door!" );
  651.     endif;
  652.     stop;
  653.   endif;
  654.   goto NOTHING;
  655.  
  656. :LETTER_M
  657.   if group.size > 1 then
  658.     L0 = select$n( player.bp );        ! Select BP item ($n=show counts)
  659.     if L0 >= 0 then                    ! Did you choose something
  660.       L2 = group.current;              ! Save current player index !
  661.       L1 = select( group );            ! Select a destination player !
  662.       if L1 >= 0 and L1 <> L2 then     ! Did choose one !
  663.         group.current = L2;            ! Restore original player !
  664.         setbp( player, L0 );           ! Select backpack item to move !
  665.         move( player.bp, player(L1) ); ! Move it !
  666.         stats;                         ! Refresh whatever is shown !
  667.       endif;
  668.     endif;
  669.   endif;
  670.   STOP;
  671.  
  672. :LETTER_N
  673.   write( "Invoke " );
  674.   L0 = select$n( player, SCROLL, GEMS );
  675.   stats;
  676.   if L0 >= 0 then
  677.     runscript( player.bp.script, "CURRITEM", INVOKE );
  678.     ! Does NOT return !
  679.   endif;
  680.   writeln( "nothing .." );
  681.   if L0 < -1 then
  682.     writeln( "You have no items that you can invoke.." );
  683.   endif;
  684.   STOP;
  685.  
  686. :LETTER_O
  687.   STOP;
  688.  
  689. :LETTER_P
  690.   STOP;
  691.  
  692. :LETTER_Q
  693.   write( "Quaff (eat or drink) " );
  694.   L0 = select$n( player, FOOD, POTION );
  695.   stats;
  696.   if L0 >= 0 then
  697.     runscript( player.bp.script, "CURRITEM", INVOKE );
  698.     ! Does NOT return !
  699.   endif;
  700.   writeln( "nothing .." );
  701.   if L0 < -1 then
  702.     writeln( "You have no items that you can eat or drink" );
  703.   endif;
  704.   STOP;
  705.  
  706. :LETTER_R
  707.   write( "Remove " );
  708.   L0 = select( player.body ); ! Any worn item !
  709.   if L0 >= 0 then
  710.     runscript( player.body.script, "CURRITEM", REMOVE );
  711.   endif;
  712.   stats;
  713.   writeln( "nothing.." );
  714.   if L0 < -1 then
  715.     writeln( "You have no items to remove!" );
  716.   endif;
  717.   STOP;
  718.  
  719. :LETTER_S
  720.   runscript( player.script, "CASTING", CAST );
  721.   STOP;
  722.  
  723. :LETTER_T
  724.   write( "Talk to " );
  725.   L0 = locate; ! Find ANYTHING !
  726.   if success then 
  727.     if npc.count and npc.x = pointx and npc.y = pointy then ! Found an NPC !
  728.       if abs(npc.x - player.x) > 2 or abs(npc.y - player.y) > 2 then
  729.         writeln( "You must get closer!" );
  730.         STOP;
  731.       endif;
  732.       writeln( npc.type );
  733.       runscript( npc.script, "OBJECT", TALK );
  734.     endif;
  735.     if abs(object.x - player.x) > 2 or abs(object.y - player.y) > 2 then
  736.       writeln( "You must get closer!" );
  737.       STOP;
  738.     endif;
  739.     writeln( object.type );
  740.     runscript( object.script, "OBJECT", TALK );
  741.   endif;
  742.   if group.x = pointx and group.y = pointy then
  743.     writeln( "yourself..?" );
  744.   else
  745.     writeln( "no one.." );
  746.   endif;
  747.   STOP;
  748.  
  749. :LETTER_U
  750.   write( "Use/Unlock " );
  751.   L0 = locate( OBJECT ); ! Find an object !
  752.   if success then 
  753.     if abs(object.x - player.x) > 2 or abs(object.y - player.y) > 2 then
  754.       writeln( "You must get closer!" );
  755.       STOP;
  756.     endif;
  757.     writeln( object.type );
  758.     runscript( object.script, "OBJECT", USE );
  759.   endif;
  760.   if world.density(pointx,pointy) = LOCKED_DOOR then
  761.     writeln( "locked door." );
  762.     if abs(pointx - player.x) > 1 or abs(pointy - player.y) > 1 then
  763.       writeln( "You must be next to it to unlock it!" );
  764.     elsif random(2) = 0 then
  765.       world.block(pointx,pointy) = world.block(pointx,pointy) - 1;
  766.       writeln( "You broke the lock!" );
  767.     else
  768.       writeln( "You failed to unlock it!" );
  769.     endif;
  770.     stop;
  771.   endif;
  772.   goto NOTHING;
  773.  
  774. :LETTER_V
  775.   if group.size > 1 then
  776.     writeln( "Who leaves the party?" );
  777.     L0 = select( group );
  778.     stats;
  779.     if player.index = 0 then
  780.       writeln( "You can't leave the party!" );
  781.       STOP;
  782.     endif;
  783.     if player.hp = 0 then
  784.       writeln( "You leave ", player.name, "'s body to the vultures.." );
  785.     elsif player.hp < 2 then
  786.       writeln( "You abandon ", player.name, ", who is almost dead.." );
  787.     else
  788.       writeln( player.name, " leaves the group." );
  789.     endif;
  790.     LEAVE(player.index);
  791.     stats;
  792.   else
  793.     writeln( "You are alone!" );
  794.   endif;
  795.   STOP;
  796.  
  797. :LETTER_W
  798.  
  799.   write( "Wear (or Wield) " );
  800.   L0 = select$n( player, WEAPON, ARMOR, RING, AMULET, STAFF, SHIELD );
  801.   if L0 >= 0 then
  802.     runscript( player.bp.script, "CURRITEM", WEAR );
  803.     ! Does NOT return !
  804.   endif;
  805.   stats;
  806.   writeln( "nothing .." );
  807.   if L0 < -1 then
  808.     writeln( "You have no items that you can wear or wield" );
  809.   endif;
  810.   STOP;
  811.  
  812. :LETTER_X
  813.   if group.vehicle.count then
  814.     ! We are riding on a vehicle !
  815.     curritem = group.vehicle;
  816.     runscript( group.vehicle.script, "CURRITEM", EXIT );
  817.   else
  818.     writeln( "You are already on foot!" );
  819.   endif;
  820.   STOP;
  821.  
  822. :LETTER_Y
  823.   STOP;
  824.  
  825. :LETTER_Z
  826.   if player.staff.count then
  827.     curritem = player.staff;
  828.     runscript( player.staff.script, "CURRITEM", invoke );
  829.   endif;
  830.   STOP;
  831.  
  832. :NOTHING
  833.   if group.x = pointx and group.y = pointy then
  834.     writeln( "yourself..?" );
  835.   else
  836.     writeln( "nothing.." );
  837.   endif;
  838.   STOP;
  839.  
  840. :SPACE
  841.   writeln( "Pass.." );
  842.   goto @0; ! Time Control !
  843.  
  844. :VIEW_CLICK
  845.   ! Did we click on ourselves? !
  846.   if group.x = pointx and group.y = pointy then
  847.     writeln( "Don't do that! It tickles.." );
  848.     STOP;
  849.   endif;
  850.   ! First, check the objects !
  851.   L2 = locate( object, pointx, pointy );
  852.   if success then
  853.     if button = 1 then
  854.       if abs(pointx - player.x) > 1 or abs(pointy - player.y) > 1 then
  855.         writeln( "You can't reach the ", object.type );
  856.         STOP;
  857.       endif;
  858.       if object.type = VEHICLE or object.type = DOOR or
  859.          object.type = SIGN    or
  860.          object.type = CHEST and object.locktype > 0 then
  861.         writeln( "Use ", object.type );
  862.         runscript( object.script, "OBJECT", USE );
  863.       else
  864.         writeln( "Get ", object.type );
  865.         runscript( object.script, "OBJECT", GET );
  866.       endif;
  867.     elsif button = 2 then
  868.       writeln( "You look at the ", object.type );
  869.       if abs(pointx - player.x) > 3 or abs(pointy - player.y) > 3 then
  870.         writeln( "You should get closer to look at the ", object.type );
  871.         STOP;
  872.       endif;
  873.       runscript( object.script, "OBJECT", LOOK );
  874.     else
  875.       writeln( "The middle button has no effect!" );
  876.       stop;
  877.     endif;
  878.   endif;
  879.   ! Next check the characters !
  880.   L2 = locate( npc, pointx, pointy );
  881.   if success then
  882.     if button = 1 then
  883.       if abs(pointx - player.x) > 2 or abs(pointy - player.y) > 2 then
  884.         writeln( "You must get nearer for conversation." );
  885.         STOP;
  886.       endif;
  887.       writeln( "Talk to ", npc.type );
  888.       runscript( npc.script, "OBJECT", TALK );
  889.     elsif button = 2 then
  890.       if abs(pointx - player.x) > 3 or abs(pointy - player.y) > 3 then
  891.         writeln( "You should get closer to look at the ", npc.type );
  892.         STOP;
  893.       endif;
  894.       writeln( "You look at the ", npc.type );
  895.       runscript( npc.script, "OBJECT", LOOK );
  896.     else
  897.       writeln( "The middle button has no effect!" );
  898.     endif;
  899.   endif;
  900.   if world.density(pointx,pointy) = HIDDEN_DOOR then
  901.     if abs(pointx - player.x) > 2 or abs(pointy - player.y) > 2 then
  902.       writeln( "You must get closer to the wall." );
  903.     else
  904.       writeln( "You found a hidden door!" );
  905.       world.block(pointx,pointy) = world.block(pointx,pointy) - 1;
  906.     endif;
  907.     stop;
  908.   endif;
  909.   if world.density(pointx,pointy) = LOCKED_DOOR then
  910.     if abs(pointx - player.x) > 1 or abs(pointy - player.y) > 1 then
  911.       writeln( "You must be next to it to unlock it!" );
  912.     else
  913.       if random(2) = 0 then
  914.         world.block(pointx,pointy) = world.block(pointx,pointy) - 1;
  915.         writeln( "You broke the lock!" );
  916.       else
  917.         writeln( "You failed to unlock it!" );
  918.       endif;
  919.     endif;
  920.     stop;
  921.   endif;
  922.   STOP;
  923.  
  924. :MENU_CLICK
  925.   ! I don't do anything with this right now.. !
  926.   STOP;
  927.  
  928. :ICON_CLICK
  929.   on pointx goto
  930.     LETTER_A,  ! Attack !
  931.     LETTER_G,  ! Get !
  932.     LETTER_D,  ! Drop !
  933.     LETTER_L,  ! Look !
  934.     LETTER_T,  ! Talk !
  935.     LETTER_C,  ! Camp Out or Sleep !
  936.     LETTER_E,  ! Enter or Exit through a door !
  937.     LETTER_I;  ! INVENTORY !
  938.   STOP;
  939.  
  940. :MNAV_CLICK
  941.      if pointx = 0 then goto SHOW_GRP;         ! Group Stats
  942.   elsif pointx = 1 then stats( player.bp );    ! Player's Inventory
  943.   elsif pointx = 2 then stats( player.body );  ! Player's Body
  944.   elsif pointx = 3 then stats( PREV );         ! Previous Player
  945.   elsif pointx = 4 then stats( NEXT );         ! Next Player
  946.   elsif pointx = 5 then paint( LARGE );        ! Full Screen Mode
  947.   endif;
  948.   STOP;
  949.  
  950. :STAT_CLICK
  951.   ! Looking at Group, selected an individual !
  952.   if pointy < group.size then
  953.     GROUP.CURRENT = pointy;
  954.     STATS( GROUP.CURRENT );        ! Display INDIVIDUAL statistics !
  955.   endif;
  956.   STOP;
  957.  
  958. :CHAR_CLICK
  959.   ! Looking at Individual (point x), clicked at item)
  960.   on pointy goto 
  961.     SHOW_GRP,    ! No item, so go back to showing the GROUP
  962.     SHOW_WPN,    ! Clicked at weapon being worn (or empty place)
  963.     SHOW_SHLD,   ! Clicked at shield being worn (or empty place)
  964.     SHOW_ARMR,   ! Clicked at armor being worn (or empty place)
  965.     SHOW_STF,    ! Clicked at staff being worn (or empty place)
  966.     SHOW_RING,   ! Clicked at ring being worn (or empty place)
  967.     SHOW_AMULET; ! Clicked at amulet being worn (or emtpy place)
  968.   STOP;
  969.  
  970. :BODY_CLICK
  971.   on pointy goto
  972.     TEMP_SKIP,   ! 0 nothing
  973.     SHOW_HND1,   ! 1 right hand
  974.     SHOW_HND2,   ! 2 left hand
  975.     SHOW_ARMR,   ! 3 torso
  976.     TEMP_SKIP,   ! 4 waist
  977.     TEMP_SKIP,   ! 5 legs
  978.     TEMP_SKIP,   ! 6 feet
  979.     TEMP_SKIP,   ! 7 hat
  980.     SHOW_AMULET, ! 8 neck
  981.     SHOW_RING,   ! 9 right ring
  982.     TEMP_SKIP;   !10 left ring
  983. :TEMP_SKIP
  984.   STOP;
  985.  
  986. :SHOW_HND1
  987.   if player.weapon.count goto SHOW_WPN;
  988.   goto SHOW_STF;
  989.   STOP;
  990.  
  991. :SHOW_HND2
  992.   if player.shield.count goto SHOW_SHLD;
  993.   goto SHOW_STF;
  994.   STOP;
  995.  
  996. :PACK_CLICK
  997.   if pointy >= 0 then
  998.     setbp( player, pointy );
  999.     gosub DO_BP_ITEM;
  1000.   endif;
  1001.   STOP;
  1002.  
  1003. :SHOW_GRP
  1004.   STATS( group ); ! Display GROUP statistics !
  1005.   STOP;
  1006.  
  1007. :SHOW_WPN
  1008.   if player.weapon.count then
  1009.     curritem = player.weapon;
  1010.     gosub DO_WORN_ITEM;
  1011.   endif;
  1012.   STOP;
  1013.  
  1014. :SHOW_SHLD
  1015.   if player.shield.count then
  1016.     curritem = player.shield;
  1017.     gosub DO_WORN_ITEM;
  1018.   endif;
  1019.   STOP;
  1020.  
  1021. :SHOW_ARMR
  1022.   if player.armor.count then
  1023.     curritem = player.armor;
  1024.     gosub DO_WORN_ITEM;
  1025.   endif;
  1026.   STOP;
  1027.  
  1028. :SHOW_STF
  1029.   if player.staff.count then
  1030.     curritem = player.staff;
  1031.     gosub DO_WORN_ITEM;
  1032.   endif;
  1033.   STOP;
  1034.  
  1035. :SHOW_RING
  1036.   if player.ring.count then
  1037.     curritem = player.ring;
  1038.     gosub DO_WORN_ITEM;
  1039.   endif;
  1040.   STOP;
  1041.  
  1042. :SHOW_AMULET
  1043.   if player.amulet.count then
  1044.     curritem = player.amulet;
  1045.     gosub DO_WORN_ITEM;
  1046.   endif;
  1047.   STOP;
  1048.  
  1049. :DO_WORN_ITEM
  1050.   if button = 1 then
  1051.     writeln( "Remove ", curritem.type, ".." );
  1052.     runscript( curritem.script, "CURRITEM", REMOVE );
  1053.   elsif button = 2 then
  1054.     writeln( "Look at ", curritem.type );
  1055.     runscript( curritem.script, "CURRITEM", LOOK );
  1056.   endif;
  1057.   return;
  1058.  
  1059. :DO_BP_ITEM
  1060.   if player.bp.count then
  1061.     curritem = player.bp;
  1062.     if button = 1 then
  1063.       if curritem.type = WEAPON or curritem.type = ARMOR or
  1064.          curritem.type = RING   or curritem.type = AMULET or
  1065.          curritem.type = SHIELD or curritem.type = STAFF then
  1066.          writeln( "Wear/Wield ", curritem.type, ".." );
  1067.          runscript( curritem.script, "CURRITEM", WEAR );
  1068.       else
  1069.          writeln( "Use ", curritem.type, ".." );
  1070.          runscript( curritem.script, "CURRITEM", USE );
  1071.       endif;
  1072.     elsif button = 2 then
  1073.       writeln( "Look at ", curritem.type );
  1074.       runscript( curritem.script, "CURRITEM", LOOK );
  1075.     endif;
  1076.   endif;
  1077.   return;
  1078.  
  1079. !---------------------------------------------------------------------------!
  1080. !---------------------------------------------------------------------------!
  1081. !---------------------------------------------------------------------------!
  1082. !---------------------------------------------------------------------------!
  1083. !---------------------------------------------------------------------------!
  1084. !
  1085. ! SUBROUTINE: HEAL_HP
  1086. !
  1087. ! Heal the players with the passage of time
  1088. !
  1089. :HEAL_HP
  1090.   ! alive and not sick !
  1091.   if player.hp > 0 and not player.poisoned then
  1092.     dec( player.energy );
  1093.     if player.energy <= 0 then
  1094.       if group.food > 0 then
  1095.         dec( group.food );
  1096.         player.energy = 255;
  1097.       else
  1098.         writeln( player.name, " goes hungry!" );
  1099.         return;
  1100.       endif;
  1101.     endif;
  1102.     if player.hp < player.mhp then
  1103.       inc( player.hp );
  1104.     endif;
  1105.   endif;
  1106.   return;
  1107.  
  1108. !
  1109. ! SUBROUTINE: HEAL_PWR
  1110. !
  1111. ! Restore magic points withthe passage of time..
  1112. !
  1113. :HEAL_PWR
  1114.   if player.hp > 0 and player.energy > 0 and player.pwr < player.mpwr then
  1115.     inc( player.pwr );
  1116.     if player.class = ELF and player.pwr < player.mpwr then
  1117.       inc( player.pwr ); ! Do elves faster.. !
  1118.     endif;
  1119.   endif;
  1120.   return;
  1121.  
  1122. !
  1123. ! SUBROUTINE to create a Random Monster
  1124. !
  1125. :NEWMONSTER
  1126.   ! Try to find a position for the monster up to 8 times..
  1127.   for L3 = 1 to 8 do
  1128.     L0 = group.x + random(8) - 4;
  1129.     L1 = group.y + random(8) - 4;
  1130.     if L0 < 0 then L0 = 0; endif;
  1131.     if L1 < 0 then L1 = 0; endif;
  1132.     if L0 >= world.x then L0 = world.x - 1; endif;
  1133.     if L1 >= world.y then L1 = world.y - 1; endif;
  1134.     if L0 <> player.x or L1 <> player.y then
  1135.       L2 = world.density(L0,L1);
  1136.       if L2 = FLAT or L2 = ROUGH or L2 = VERY_ROUGH or L2 = SWAMP or L2 = DESERT then
  1137.         ! Create a LAND-BASED monster !
  1138.         L2 = random(3);    ! Small, Medium or Large (0-2) !
  1139.         L3 = random(L2+3); ! Select a graphics block for that size (0-4) !
  1140.         if world.type = DUNGEON then
  1141.           L4 = DEFCAVEBLK( L3 );            ! Leader   !
  1142.           L5 = DEFCAVEBLK( random(L3+1) );  ! Follower !
  1143.           L6 = CAVE_MONSTER;
  1144.         elsif world.type = HAUNTED then
  1145.           L4 = DEFSPOOKBLK( L3 );           ! Leader   !
  1146.           L5 = DEFSPOOKBLK( random(L3+1) ); ! Follower !
  1147.           L6 = SPOOK_MONSTER;
  1148.         else
  1149.           ! OUTDOORS or ARENA !
  1150.           L4 = DEFLANDBLK( L3 );            ! Leader   !
  1151.           L5 = DEFLANDBLK( random(L3+1) );  ! Follower !
  1152.           L6 = LAND_MONSTER;
  1153.         endif;
  1154.         goto DOIT;
  1155.       elsif L2 = DEEP_WATER then
  1156.         ! Create a WATER-BOUND monster !
  1157.         L2 = random(3);        ! Small, Medium, Large (0-2) !
  1158.         if random(5) = 0 then  ! Pirate Ship (SPECIAL CASE) !
  1159.           L4 = DEFWATERBLK(4); ! Fifth water monster is a ship !
  1160.           L5 = DEFWATERBLK(4); ! Followers are ships also !
  1161.         else
  1162.           L3 = random(L2+2); ! Select a graphics block for that size (0-3) !
  1163.           L4 = DEFWATERBLK( L3 );            ! Leader   !
  1164.           L5 = DEFWATERBLK( random(L3+1) );  ! Follower !
  1165.         endif;
  1166.         L6 = WATER_MONSTER;
  1167.         goto DOIT;
  1168.       endif;
  1169.     endif;
  1170.   endfor;
  1171.   return; ! Tried 8 Times, give up !
  1172.  
  1173. :DOIT
  1174.   new(npc,L0,L1,L4);
  1175.   npc.type   = HOSTILE;       ! NPC Type
  1176.   npc.stats  = defstat(L2);   ! Statistics Record
  1177.   npc.block2 = L5;            ! Followers (if any)
  1178.   npc.class  = L6;            ! Monster Class
  1179.  
  1180.   ! Gold carried
  1181.   if world.type = ARENA then
  1182.     npc.value = random(50)+1; ! Very little money (Up to 5 gold pieces) !
  1183.   else
  1184.     npc.value = 0;
  1185.   endif;
  1186.  
  1187.   !
  1188.   ! # of monsters in the group.  The formula is based on L2 (monster size).
  1189.   ! If small  (L2=0), then # = random( group.size + 6 ) + 1
  1190.   ! If medium (L2=1), then # = random( group.size + 3 ) + 1
  1191.   ! if large  (L2=2), then # = random( group.size ) + 1
  1192.   npc.count = random( group.size + (2 - L2) * 3 ) + 1;
  1193.  
  1194.   L254 = TRUE; ! Monster has been created !
  1195.  
  1196.   voice( "ALERT", 1000 );
  1197.   return;
  1198.  
  1199. !
  1200. ! This SUBROUTINE will hit every player in the group by using the
  1201. ! subroutine HITPLAYER.
  1202. !
  1203. :HITGROUP
  1204.   foreach player do
  1205.     gosub HITPLAYER;
  1206.   endfor;
  1207.   return;
  1208.  
  1209. !
  1210. ! This SUBROUTINE will decrement the hit points of the current
  1211. ! group member.  It checks to see if the player has died or lost
  1212. ! consciousnes.  The variable S0 contains the reason for the hit.
  1213. !
  1214. :HITPLAYER
  1215.   if player.hp > 0 then
  1216.     dec( player.hp );
  1217.     if player.hp = 0 then
  1218.       writeln( player.name, " has died of ", s0, "!" );
  1219.     elsif player.hp = 1 then
  1220.       writeln( player.name, " has fainted from ", s0, "!" );
  1221.     else
  1222.       writeln( player.name, " weakens!" );
  1223.     endif;
  1224.   endif;
  1225.   return;
  1226.  
  1227. !------------------------------------------------------------------------!
  1228. !
  1229. ! SUBROUTINE: M1_INVOKE
  1230. !
  1231. ! Type 1 Magic - Affects the person invoking the magic..
  1232. !
  1233. ! This code is equivalent to the one in OBJECT.SCR.  When resting, 
  1234. ! rings and amulets that have magical properties will re-invoke their
  1235. ! effect when you wake up.
  1236. !
  1237. !------------------------------------------------------------------------!
  1238. :M1_INVOKE
  1239. !------------------------------------------------------------------------!
  1240.  
  1241.   if curritem.cursed then
  1242.     if curritem.permanent then
  1243.       L0 = msgbox( ERROR, 1, "Ok", "WARNING: Cursed Item with PERMANENT effect are not recommended!" );
  1244.       curritem.permanent = FALSE;
  1245.     endif;
  1246.   endif;
  1247.  
  1248.   if curritem.charges < 255 then
  1249.     dec(curritem.charges);  ! 255 means forever !
  1250.   endif;
  1251.  
  1252.   on curritem.class goto
  1253.     M1_NONE,    M1_CURE,    M1_HEAL,    M1_POISON,    M1_RESTORE,
  1254.     M1_STR,     M1_DEX,     M1_SPD,     M1_AIM,       M1_AC,
  1255.     M1_HP,      M1_IQ,      M1_PWR;
  1256.  
  1257. :M1_NONE
  1258.   return;
  1259.  
  1260. :M1_CURE
  1261.   if player.poisoned then
  1262.     player.poisoned = 0;
  1263.     writeln( player.name, " is now cured." );
  1264.   endif;
  1265.   return;
  1266.  
  1267. :M1_HEAL
  1268.   if player.hp > 0 and player.hp < player.mhp then
  1269.     if curritem.units > 0 then
  1270.       L(0) = curritem.units;                   ! always heals the same points !
  1271.     else
  1272.       L(0) = random(player.mhp - player.hp)+1; ! heal a random number of points !
  1273.     endif;
  1274.     if player.hp + L(0) < player.mhp then
  1275.       writeln( player.name, " heals ", L(0), " hit points.." );
  1276.       inc( player.hp, L(0) );
  1277.     else
  1278.       writeln( player.name, " has been completely healed!" );
  1279.       player.hp = player.mhp;
  1280.     endif;
  1281.   endif;
  1282.   return;
  1283.  
  1284. :M1_POISON
  1285.   if NOT player.poisoned then
  1286.     player.poisoned = TRUE;
  1287.     writeln( player.name, " is poisoned!" );
  1288.   endif;
  1289.   return;
  1290.  
  1291. :M1_RESTORE
  1292.   if player.hp < player.mhp then
  1293.     player.hp = player.mhp;
  1294.     writeln( player.name, " is completely healed!" );
  1295.   endif;
  1296.   return;
  1297.  
  1298. :M1_STR
  1299.   if curritem.cursed then
  1300.     player.str = 0;
  1301.   else
  1302.     inc( player.str, curritem.units );
  1303.     if curritem.permanent then
  1304.       inc( player.mstr, curritem.units );
  1305.     endif;
  1306.     writeln( player.name, "'s strength increased by ", curritem.units, "!" );
  1307.   endif;
  1308.   return;
  1309.  
  1310. :M1_DEX
  1311.   if curritem.cursed then
  1312.     player.dex = 0;
  1313.   else
  1314.     inc( player.dex, curritem.units );
  1315.     if curritem.permanent then
  1316.       inc( player.mdex, curritem.units );
  1317.     endif;
  1318.     writeln( player.name, "'s dexterity increased by ", curritem.units, "!" );
  1319.   endif;
  1320.   return;
  1321.  
  1322. :M1_SPD
  1323.   if curritem.cursed then
  1324.     player.spd = 0;
  1325.   else
  1326.     inc( player.spd, curritem.units );
  1327.     if curritem.permanent then
  1328.       inc( player.mspd, curritem.units );
  1329.     endif;
  1330.     writeln( player.name, "'s speed increased by ", curritem.units, "!" );
  1331.   endif;
  1332.   return;
  1333.  
  1334. :M1_AIM
  1335.   if curritem.cursed then
  1336.     player.aim = 0;
  1337.   else
  1338.     inc( player.aim, curritem.units );
  1339.     if curritem.permanent then
  1340.       inc( player.maim, curritem.units );
  1341.     endif;
  1342.     writeln( player.name, "'s aim increased by ", curritem.units, "!" );
  1343.   endif;
  1344.   return;
  1345.  
  1346. :M1_AC
  1347.   if curritem.cursed then
  1348.     player.ac = 0;
  1349.   else
  1350.     inc( player.ac, curritem.units );
  1351.     if curritem.permanent then
  1352.       inc( player.mac, curritem.units );
  1353.     endif;
  1354.     writeln( player.name, "'s armor class increased by ", curritem.units, "!" );
  1355.   endif;
  1356.   return;
  1357.  
  1358. :M1_HP
  1359.   if curritem.cursed then
  1360.     player.hp = player.hp / 3 + 1;
  1361.   else
  1362.     inc( player.hp, curritem.units );
  1363.     if curritem.permanent then
  1364.       inc( player.mhp, curritem.units );
  1365.     endif;
  1366.     writeln( player.name, "'s hit points increased by ", curritem.units, "!" );
  1367.   endif;
  1368.   return;
  1369.  
  1370. :M1_IQ
  1371.   if curritem.cursed then
  1372.     player.iq = 0;
  1373.   else
  1374.     inc( player.iq, curritem.units );
  1375.     if curritem.permanent then
  1376.       inc( player.miq, curritem.units );
  1377.     endif;
  1378.     writeln( player.name, "'s i.q. increased by ", curritem.units, "!" );
  1379.   endif;
  1380.   return;
  1381.  
  1382. :M1_PWR
  1383.   if player.class = ELF or player.class = WIZARD then
  1384.     if curritem.cursed then
  1385.       player.pwr = 0;
  1386.     else
  1387.       inc( player.pwr, curritem.units );
  1388.       if curritem.permanent then
  1389.         inc( player.mpwr, curritem.units );
  1390.       endif;
  1391.       writeln( player.name, "'s power increased by ", curritem.units, "!" );
  1392.     endif;
  1393.   else
  1394.     write( player.name, " has a headache all night long.." );
  1395.     if player.hp < 3 then
  1396.       writeln( " and dies!" );
  1397.       player.hp = 0;
  1398.     else
  1399.       writeln;
  1400.       dec( player.hp, 2 );
  1401.     endif;
  1402.   endif;
  1403.   return;
  1404.  
  1405. !-----------------------------------------------------------------------!
  1406. ! Allow ONE minute of time to go bye in the game's clock                !
  1407. !-----------------------------------------------------------------------!
  1408. :CLOCK_TICK
  1409.  
  1410.   if minute < MinutesInAnHour - 1 then
  1411.     inc( minute );
  1412.   else
  1413.     minute = 0;
  1414.     if hour < HoursInADay - 1 then
  1415.       inc( hour );
  1416.     else
  1417.       hour = 0;
  1418.       if day < DaysInAMonth - 1 then
  1419.         inc( day );
  1420.       else
  1421.         day = 0;
  1422.         if month < MonthsInAYear - 1 then
  1423.           inc( month );
  1424.         else
  1425.           month = 0;
  1426.           inc( year );
  1427.         endif;
  1428.       endif;
  1429.       if hour = sunrise then
  1430.         writeln( "The sun rises in the east. " );
  1431.         ! gosub DAYNIGHT;
  1432.       elsif hour = sunset then
  1433.         writeln( "The sun sets in the west. " );
  1434.         ! gosub DAYNIGHT;
  1435.       endif;
  1436.     endif;
  1437.   endif;
  1438.   return;
  1439.  
  1440. !-----------------------------------------------------------------------!
  1441. ! Print the current time                                                !
  1442. !-----------------------------------------------------------------------!
  1443. :CLOCK_PRINT
  1444.  
  1445.   L1 = HoursInADay / 2; ! Noon !
  1446.   if hour > L1 then
  1447.     if minute = 0 then
  1448.       writeln( "It's ", hour - L1, "pm" );
  1449.     elsif minute < 10 then
  1450.       writeln( "It's ", hour - L1, ":0", minute, "pm" );
  1451.     else
  1452.       writeln( "It's ", hour - L1, ":", minute, "pm" );
  1453.     endif;
  1454.   elsif hour = 0 then
  1455.     writeln( "It's midnight" );
  1456.   elsif hour = L1 then
  1457.     writeln( "It's noon" );
  1458.   else
  1459.     if minute = 0 then
  1460.       writeln( "It's ", hour, "am" );
  1461.     elsif minute < 10 then
  1462.       writeln( "It's ", hour, ":0", minute, "am" );
  1463.     else
  1464.       writeln( "It's ", hour, ":", minute, "am" );
  1465.     endif;
  1466.   endif;
  1467.   return;
  1468. !
  1469.  
  1470. !:DAYNIGHT
  1471. !
  1472. ! Ideally, we should reflect sunrise and sunset by some visual
  1473. ! change in the game.  For example:
  1474. !
  1475. ! If we wanted to create a "daylight"/"night-type" effect, we have
  1476. ! two options. One, create two landscape sets that are identical
  1477. ! except one uses darker colors (you really need 256 colors for 
  1478. ! this), as follows:
  1479. !
  1480. ! if world.type = OUTDOORS then
  1481. !   if hour = sunrise then
  1482. !     world.landscape = 0;
  1483. !   elsif hour = sunset then
  1484. !     world.landscape = 1;
  1485. !   endif;
  1486. ! endif;
  1487. ! return;
  1488. !
  1489. ! The second one is to have a second PALETTE of colors, which
  1490. ! are darker than the standard palette.  You can then just
  1491. ! change the palette
  1492. !
  1493. ! if hours = sunset then loadpalette( "NIGHT.PAL" );
  1494. ! elsif hour = sunrise then loadpalette( "DAY.PAL" );
  1495. ! return;
  1496. !
  1497. ! However, I did not implement 'loadpalette()' yet, so this last
  1498. ! option is not possible right now. :)
  1499. !
  1500.  
  1501. !------------------------------------------------------
  1502. ! Attack an NPC
  1503. !------------------------------------------------------
  1504.  
  1505. :ATTACK_NPC
  1506.   ! L3 contains distance to current npc per LOCATE command !
  1507.   ! L4 the weapon class (blunt, missile, etc)
  1508.   ! L5 the range (distance) you can reach with this weapon
  1509.   ! L6 is non-zero if type of ammo that is needed by the weapon
  1510.   ! L7 is the damage points done
  1511.   if player.weapon.count then 
  1512.     L4 = player.weapon.class;
  1513.     L5 = player.weapon.range;
  1514.     L6 = player.weapon.ammoneeded;
  1515.     L7 = player.weapon.damage;
  1516.   else
  1517.     L4 = BLUNT;
  1518.     L5 = 1;
  1519.     L6 = 0;
  1520.     L7 = 1;
  1521.   endif;
  1522.   if L4 = MISSILE then
  1523.     for L10 = 0 to 15 do
  1524.       setbp( player, L10 );
  1525.       if player.bp.count then
  1526.         if player.bp.type = AMMO and player.bp.ammotype = L6 then
  1527.           if player.bp.count < 255 then
  1528.             dec(player.bp.count);          ! Count of 255 means it never ends? !
  1529.           endif;
  1530.           L5 = max( L5, player.bp.range ); ! Use ammo's range if higher !
  1531.           inc( L7, player.bp.damage );     ! If ammunition causes extra damage !
  1532.           L6 = L10;                        ! Keep AMMO's BP here !
  1533.           goto FOUND_AMMO;
  1534.         endif;
  1535.       endif;
  1536.     endfor;
  1537.     writeln( "Out of ammo! Using hands!" );
  1538.     L4 = BLUNT;
  1539.     L5 = 1;
  1540.     L6 = 0;
  1541.     L7 = 1;
  1542. :FOUND_AMMO
  1543.   endif;
  1544.   if L5 < L3 then
  1545.     writeln( "You have to get closer!" );
  1546.     stop;
  1547.   endif;
  1548.  
  1549.   ! HERE I COULD 'RANDOMIZE' THE DAMAGE, BUT I'LL LET IT BE CONSTANT FOR NOW !
  1550.  
  1551.   ! For contact weapons, STRENGTH increases damage !
  1552.   if L4 = BLUNT or L4 = EDGED then
  1553.     inc( L7, adjustments( player.str ) );
  1554.   endif;
  1555.  
  1556.   ! Now, we have to figure out if we missed !
  1557.   if L4 = MISSILE then
  1558.     ! For missile weapon, hit 5 out of 10, adjusted by AIM !
  1559.     if random( 10 ) + adjustments( player.aim ) < 5 then
  1560.       writeln( player.name, " missed.." );
  1561.       voice( "BadAim", 1000 );
  1562.     else
  1563.       gosub HIT_NPC;
  1564.     endif;
  1565.   else
  1566.     ! For non-missile weapon, hit 7 out of 10 adjusted up by the
  1567.     ! player's dexterity and down by the NPC's dexterity
  1568.     if random(10) + adjustments(player.dex) - adjustments(npc.dex) < 3 then
  1569.       writeln( player.name, " missed.." );
  1570.       voice( "Swish", 1000 );
  1571.     else
  1572.       gosub HIT_NPC;
  1573.     endif;
  1574.   endif;
  1575.   stop;
  1576.  
  1577. :HIT_NPC
  1578.  
  1579.   L7 = max( L7, 1 ); ! At least one HP of damage !
  1580.   if npc.hp > 1 and npc.ac > 0 then ! Armor Class protects the NPC !
  1581.     L8 = random( npc.ac+1 ); ! Absorb 0 to npc.ac damage points !
  1582.     if L8 >= L7 then
  1583.       writeln( npc.type, "'s armor absorbs the impact!" );
  1584.       voice( "Clank", 1000 );
  1585.       return;
  1586.     endif;
  1587.     dec( L7, L8 ); ! Reduce damage by L8 amount !
  1588.   endif;
  1589.  
  1590.   ! Fast PLAYERS get to hit more than once !
  1591.   if player.spd > npc.spd then
  1592.     L9 = (player.spd - npc.spd) / 10 + 1;
  1593.   else 
  1594.     L9 = 1;
  1595.   endif;
  1596.   L10 = L9; ! Original # of Moves !
  1597.   while L9 > 0 and npc.count do
  1598.     if npc.hp > L7 then
  1599.       if L9 <> L10 then
  1600.         write( npc.type, " hit - again!" );
  1601.       else
  1602.         write( npc.type, " hit!" );
  1603.       endif;
  1604.       dec( npc.hp, L7 );
  1605.       on random(3) gosub :V1, :V2, :V3;
  1606.     else
  1607.       write( npc.type, " killed!" );
  1608.       voice( "YouKill", 1000 );
  1609.       L7 = npc.hp;
  1610.       ! Now is the perfect time to GENERATE RANDOM TREASURE !
  1611.       gosub TREASURE;
  1612.       npc.count = 0; ! Actually Kill the NPC !
  1613.     endif;
  1614.     writeln( " (", L7, " points)" );
  1615.     inc( player.exp, L7 ); 
  1616.     dec(L9);
  1617.   endwhile;
  1618.  
  1619.   return;
  1620.  
  1621. :V1 voice( "Argh",   1000 ); return;
  1622. :V2 voice( "Ouch",   1000 ); return;
  1623. :V3 voice( "Whoosh", 1000 ); return;
  1624.  
  1625. !------------------------------------
  1626. :TREASURE
  1627. !------------------------------------
  1628. ! Generate random treasure
  1629.  
  1630.   ! First, leave the contents of the NPCs backpack..
  1631.   foreach npc.bp do
  1632.     drop( npc.bp, -npc.count, npc.x, npc.y ); ! Drop a copy of this item
  1633.   endfor;
  1634.  
  1635.   ! Now generate a random treasure
  1636.   on random(4) goto GT_NONE, GT_GOLD, GT_CHEST, GT_SPECIAL;
  1637. :GT_NONE
  1638.   return;
  1639.  
  1640. :GT_GOLD
  1641.   new( object, npc.x, npc.y, GOLDSACK );
  1642.   object.weight = random( player.mhp ) + 1;
  1643.   object.value  = object.weight * 10;
  1644.   return;
  1645.  
  1646. :GT_CHEST
  1647.   new( object, npc.x, npc.y, CHEST );
  1648.   object.class  = NORMAL_CHEST;
  1649.   object.weight = random( player.mhp ) + 1;
  1650.   object.value  = object.weight * 10;
  1651.   object.locktype = random(2); ! 0=None, 1+ = Key !
  1652.   object.traptype = random(3); ! 0=None, 1=Poison, 2+ = Bomb !
  1653.   return;
  1654.  
  1655. :GT_SPECIAL
  1656.   ! AMULET=5,RING=6,POTION=7,SCROLL=8,STAFF=9
  1657.   new( object, npc.x, npc.y, AMULET + random(5) );
  1658.   if object.type = SCROLL or object.type = STAFF then ! SCROLL or STAFF !
  1659.     object.class  = random(15)+1; ! See OBJECT CLASS in DCCTOKEN.DAT !
  1660.   else
  1661.     object.class  = random(12)+1; ! See OBJECT CLASS in DCCTOKEN.DAT !
  1662.   endif;
  1663.   object.weight = 1;
  1664.   if object.type = RING or object.type = AMULET or object.type = STAFF then
  1665.     object.charges = random( player.level ) + 1;
  1666.   endif;
  1667.   if object.type = RING or object.type = AMULET or object.type = POTION then
  1668.     object.units  = random( player.mhp ) + 1;
  1669.     object.permanent = (random(100) = 0); ! One out of 100 !
  1670.   endif;
  1671.   if object.permanent then
  1672.     object.value  = 1000;
  1673.     object.weight =    2;
  1674.   else
  1675.     object.value =   10;
  1676.   endif;
  1677.   return;
  1678.  
  1679. !------------------------------------
  1680. :NEW_LEVEL
  1681. !------------------------------------
  1682.  
  1683.   L10 =   1;  ! Start with level 1
  1684.   L11 = 200;  ! Next level is at 200 
  1685.   while L11 < player.exp do
  1686.     inc( L11, L11 ); ! Each level is TWICE as much as the previous one !
  1687.     inc( L10, 1 );
  1688.   endwhile;
  1689.   if L10 > player.level then    ! New Level !
  1690.     L12 = random( player.level ) + 1;  ! First, give some hit points !
  1691.     write( "New level! ", player.name, " gained ", L12, "hp " );
  1692.     inc( player.level );
  1693.     inc( player.mhp, L12 );     ! Permanent Increase !
  1694.     inc( player.hp, L12 );      ! Reflect the new HP immediatly !
  1695.  
  1696.     ! Now increase one ore more attributes depending on the class !
  1697.     L12 = random(player.level + 1) + 1; ! Start with this many points !
  1698.     if L12 > 5 then
  1699.       L12 = random(10); ! Make more than 5 points 'unlikely' but possible
  1700.     endif;
  1701.     on player.class goto
  1702.       :EX_HUMAN,
  1703.       :EX_ELF,
  1704.       :EX_DWARF,
  1705.       :EX_WIZARD,
  1706.       :EX_ARCHER,
  1707.       :EX_FIGHTER;
  1708.   endif;
  1709.   return; ! No new level !
  1710.  
  1711. :EX_HUMAN  ! Humans and 'unknown'
  1712.     inc( player.mstr, L12 );
  1713.     writeln( "and ", L12, " str." );
  1714.     return;
  1715.  
  1716. :EX_ELF
  1717.     inc( player.miq, L12 + L12 ); ! Elf gains intelligence twice as fast !
  1718.     writeln( "and ", L12, " iq." );
  1719.     return;
  1720.  
  1721. :EX_DWARF
  1722.     L13 = random(L12);
  1723.     inc( player.mstr, L12 - L13 ); ! Dwarf gains some strength !
  1724.     inc( player.mdex, L13 );       ! and some dexterity        !
  1725.     writeln( ", ", L12 - L13, " str and ", L13, " dex." );
  1726.     return;
  1727.  
  1728. :EX_WIZARD
  1729.     inc( player.miq, L12 ); ! Wizards gain intelligence !
  1730.     writeln( "and ", L12, " iq." );
  1731.     return;
  1732.  
  1733. :EX_ARCHER
  1734.     L13 = random(L12);
  1735.     inc( player.maim, L12 - L13 ); ! Dwarf gains some aim !
  1736.     inc( player.mspd, L13 );       ! and some speed       !
  1737.     writeln( ", ", L12 - L13, " aim and ", L13, " speed." );
  1738.     return;
  1739.  
  1740. :EX_FIGHTER
  1741.     inc( L12, random(L12) );       ! Fighters gain strength more quickly !
  1742.     inc( player.mstr, L12 );
  1743.     writeln( "and ", L12, " str." );
  1744.     return;
  1745.  
  1746. !
  1747. ! MOVING THE CHARACTERS
  1748. !
  1749.  
  1750. :MOVE_UP
  1751.   L3 =  0; L4 = -1; goto DO_MOVE;
  1752.  
  1753. :MOVE_DN
  1754.   L3 =  0; L4 =  1; goto DO_MOVE;
  1755.  
  1756. :MOVE_LF
  1757.   L3 = -1; L4 =  0; goto DO_MOVE;
  1758.  
  1759. :MOVE_RT
  1760.   L3 =  1; L4 =  0; goto DO_MOVE;
  1761.  
  1762. :MOVE_UL
  1763.   L3 = -1; L4 = -1; goto DO_MOVE;
  1764.     
  1765. :MOVE_DL
  1766.   L3 = -1; L4 =  1; goto DO_MOVE;
  1767.  
  1768. :MOVE_UR
  1769.   L3 =  1; L4 = -1; goto DO_MOVE;
  1770.  
  1771. :MOVE_DR
  1772.   L3 =  1; L4 =  1; goto DO_MOVE;
  1773.  
  1774. :DO_MOVE
  1775.   L0 = player.x + L3;
  1776.   L1 = player.y + L4;
  1777.   if world.wrap_around then
  1778.     if L0 < 0 then
  1779.       gosub NOTFIGHTING;
  1780.       L0 = world.x - 1;
  1781.     elsif L0 >= world.x then
  1782.       gosub NOTFIGHTING;
  1783.       L0 = 0;
  1784.     endif;
  1785.     if L1 < 0 then
  1786.       gosub NOTFIGHTING;
  1787.       L1 = world.y - 1;
  1788.     elsif L1 >= world.y then
  1789.       gosub NOTFIGHTING;
  1790.       L1 = 0;
  1791.     endif;
  1792.   else
  1793.     if L0 < 0 or L0 >= world.x or L1 < 0 or L1 >= world.y then
  1794.       gosub NOTFIGHTING;
  1795.       s0 = swriteln( "Do you want to leave ", world.name, "?" );
  1796.       L0 = msgbox( QUESTION, 2, "Yes", "No", S0 );
  1797.       if L0 = 0 then
  1798.         world.door = world.edge_door;
  1799.         runscript( WORLD, "WORLDDEF", EXIT );
  1800.         ! 
  1801.         ! NOTE: We could just run "enter( world.edge_door );" instead
  1802.         ! of the above two lines.  The difference is that when you
  1803.         ! run ENTER( door ), the driver does NOT call the @EXIT
  1804.         ! routine in the current world.  A minor but important
  1805.         ! difference. The reason for this, is that the behaviour of
  1806.         ! ENTERING A WORLD (i.e. load the world, call script at @GET,
  1807.         ! call script at @ENTER) is a feature of the driver, but
  1808.         ! the @EXIT entry point is handled entirely by the scripts
  1809.         ! themselves. If you don't want to take any action when you
  1810.         ! exit a world, you can change the above two lines to a 
  1811.         ! simple call to the ENTER() function.
  1812.         !
  1813.       endif;
  1814.       stats;
  1815.       STOP; 
  1816.     endif;
  1817.   endif;
  1818.   !
  1819.   !
  1820.   ! No. Do a generic check for objects and landscaping 
  1821.   ! density.
  1822.   !
  1823.  
  1824.   ! Note L0, L1 are already set to the correct X/Y location
  1825.   ! L2 needs to be 0 for NPC checking, 1 for PLAYER checking
  1826.   L2 = 1;
  1827.   gosub CHK_A_MOVE; ! Move player, current NPC not important !
  1828.   if not L2 then
  1829.     if s0 <> "" then
  1830.       writeln(s0);
  1831.     endif;
  1832.     STOP;
  1833.   endif;
  1834.  
  1835.   ! Go Ahead and Move
  1836.   if fighting then
  1837.     if group.vehicle.count then ! Inside a vehicle !
  1838.       group.x = L0; group.y = L1;
  1839.     else
  1840.       if group.size > 1 then
  1841.         ! Must check that we are not standing in another
  1842.         ! player's toes..
  1843.         L2 = player.index; ! Store Current Player Index
  1844.         S0 = player.name;  ! Store player's name
  1845.         foreach player do
  1846.           if player.index <> L2 and player.hp > 0 then
  1847.             if L0 = player.x and L1 = player.y then
  1848.               writeln( S0, " bumps into ", player.name );
  1849.               player.index = L2; ! Restore Index !
  1850.               STOP;
  1851.             endif;
  1852.           endif;
  1853.         endfor;
  1854.         player.index = L2; ! Restore Index !
  1855.       endif;
  1856.       ! Go ahead and move !
  1857.       player.x = L0; player.y = L1;
  1858.     endif;
  1859.   else
  1860.     group.x  = L0; group.y  = L1;
  1861.     ! Check for Trap doors !
  1862.     if L0 > 0 and L1 > 0 then
  1863.       for L5 = 0 to 31 do
  1864.         if L0 = world.doorx(L5) and L1 = world.doory(L5) then
  1865.           if world.trapdoorswitch(L5) then
  1866.             world.door = L5; ! Use this door !
  1867.             runscript( WORLD, "WORLDDEF", EXIT );
  1868.           endif;
  1869.         endif;
  1870.       endfor;
  1871.     endif;
  1872.   endif;
  1873.   STOP;
  1874.  
  1875.  
  1876. :NOTFIGHTING
  1877.   if fighting then
  1878.     writeln( "You can't leave during a fight.." );
  1879.     stop;
  1880.   endif;
  1881.   return;
  1882.  
  1883. :FKEY1
  1884. ! Help !
  1885.   view_pcx( "ANYFRAME.PCX" );
  1886.   setframe( "ANYFRAME.PCX", 20, 20, 20, 20 );
  1887.   pwriteln( "The following commands are defined:" );
  1888.   pwriteln;
  1889.   pwriteln( "A)ttack, ", "C)amp, ", "D)rop, ", "E)nter, ", "G)et, ",
  1890.    "I)nventory, ", "L)ook, ", "iN)voike, ", "Q)uaff (eat or drink), ",
  1891.    "R)emove, ", "S)pell, ", "T)alk, ", "U)se, ", "V)acate, ",
  1892.    "W)ield/Wear, ", "eX)it, ", "Z)ap (with staff)" );
  1893.   pwriteln;
  1894.   pwriteln( "You may also use:" );
  1895.   pwriteln( "F1=Help, ", "F2=Save, ", "F3=Sound, ", "F4=Restore, ",
  1896.    "F6=Restart, ", "F10=Exit", " and <ALT>V to set the VOLUME" );
  1897.   pwriteln;
  1898.   pwriteln( "Press [SPACE] to continue" );
  1899.   pause;
  1900.   paint( window );
  1901.   STOP;
  1902.  
  1903. :FKEY2
  1904.   L0 = getnum( "Save in what slot?", 0, 999 );
  1905.   if L0 >= 0 then
  1906.     save( L0 );
  1907.     stop;
  1908.   endif;
  1909.   continue;
  1910.  
  1911. :FKEY3
  1912.   sound = not sound;
  1913.   if sound then
  1914.     writeln( "Sound is now on!" );
  1915.   else
  1916.     writeln( "Sound is now off!" );
  1917.   endif;
  1918.   stop;
  1919.  
  1920. :ALT_V
  1921.   L3 = select( "Low (6)", "Medium (9)", "Normal (12)", "High (15)" );
  1922.   if L3 >= 0 then
  1923.     L3 = L3 * 3 + 6;
  1924.     VOLUME( L3, L3 );
  1925.     voice( "WAKECALL", 1000 );
  1926.   endif;
  1927.   stop;
  1928.  
  1929. :FKEY4
  1930.   L0 = getnum( "Restore from what slot?", 1, 999 );
  1931.   if L0 > 0 then
  1932.     restore( L0 );
  1933.     writeln( "RESTORE OF SLOT ", L0, " FAILED!" );
  1934.   endif;
  1935.   stop;
  1936.  
  1937. :FKEY5
  1938.   savepcx( "SCRNSAVE.PCX" );
  1939.   stop;
  1940.  
  1941. :FKEY6
  1942.   L0 = msgbox( QUESTION, 2, "Yes", "No", "Do you really want to RESTART?" );
  1943.   if L0 = 0 then
  1944.     restart;
  1945.     writeln( "RESTART FAILED!" );
  1946.   endif;
  1947.   stats;
  1948.   stop;
  1949.  
  1950. :FKEY7
  1951.   foreach player do
  1952.     player.level = 10;
  1953.   endfor;
  1954.   stop;
  1955.  
  1956. :FKEY8
  1957.   if split then paint( large ); else paint( small ); endif;
  1958.   stop;
  1959.  
  1960. :FKEY9
  1961.   runscript( "test", 0 );
  1962.   stop;
  1963.  
  1964. :FKEY10
  1965.   if fighting then
  1966.     writeln( "Press ESCape to stop the fight, then F10 to exit!" );
  1967.     stop;
  1968.   endif;
  1969.   writeln( "See you later..." );
  1970.   save(0);
  1971.   end_game;
  1972.  
  1973. !
  1974. ! Routine to verify if a location can be occupied by
  1975. ! a character (player or NPC).
  1976. !
  1977. !  L0 = x, L1 = y, L2 = 1/player, 0/npc
  1978. !  L3 = delta on X, L4=delta on Y for guard checking
  1979. !
  1980. ! Returns L2 = NO (0) or L2 = YES (1)
  1981. !
  1982. :CHK_A_MOVE
  1983.  
  1984.   S0 = ""; ! No Return Message to start with .. !
  1985.  
  1986.   if L2 then                   ! player !
  1987.     L21 = group.vehicle.class;
  1988.   elsif npc.class = WATER_MONSTER then ! Water Monster !
  1989.     L21 = BOAT;
  1990.   else
  1991.     L21 = WALKING;
  1992.   endif;
  1993.  
  1994.   L2 = NO;
  1995.  
  1996.   ! Check for another character in the way !
  1997.   L20 = locate( npc, L0, L1 );
  1998.   if L20 >= 0 then
  1999.     s0 = "There is someone standing in your way!";
  2000.     return;
  2001.   endif;
  2002.  
  2003.   ! Check for GUARDS !
  2004.   ! NOTE: We could just check every NPC with a loop as follows:
  2005.   !   foreach NPC do
  2006.   !     if npc.type = GUARD then
  2007.   !       if abs(npc.x - L0) < 2 and abs(npc.y - L1) < 2 then
  2008.   !         S0 = "There is a GUARD there!";
  2009.   !         return;
  2010.   !       endif;
  2011.   !     endif;
  2012.   !   endfor;
  2013.   ! But the loop might cause unnecesary disk accesses if you have
  2014.   ! a large number of NPCs, because the backpacks of the NPCs are
  2015.   ! kept on disk and only a small number are kept in memory.
  2016.   ! An alternative is to use the VISIBLE qualification as follows:
  2017.   !   foreach VISIBLE npc do
  2018.   !     ...
  2019.   !   endfor;
  2020.   ! This will limit the number of NPCs being scanned, but it is 
  2021.   ! still not the best way.
  2022.   ! The following is better. It uses the LOCATE command to search
  2023.   ! for guards at specific X/Y locations, thus it only loads an
  2024.   ! NPC's backpack if there IS an NPC at the x/y location.
  2025.   !
  2026.   ! -> MUCH BETTER:
  2027.   L2 = YES; ! Assume OK !
  2028.   if L3 then ! Moving on X !
  2029.     L20 = locate( npc, L0+L3, L1 );
  2030.     if success then gosub check_guard; endif;
  2031.     L20 = locate( npc, L0+L3, L1+1 );
  2032.     if success then gosub check_guard; endif;
  2033.     L20 = locate( npc, L0+L3, L1-1 );
  2034.     if success then gosub check_guard; endif;
  2035.   endif;
  2036.   if L4 then ! Moving on Y !
  2037.     L20 = locate( npc, L0  , L1+L4 );
  2038.     if success then gosub check_guard; endif;
  2039.     L20 = locate( npc, L0+1, L1+L4 );
  2040.     if success then gosub check_guard; endif;
  2041.     L20 = locate( npc, L0-1, L1+L4 );
  2042.     if success then gosub check_guard; endif;
  2043.   endif;
  2044.   if not L2 then
  2045.     return;
  2046.   endif;
  2047.   L2 = NO; ! Keep Checking !
  2048.  
  2049.   ! Check for an OBJECT in the way !
  2050.   L20 = locate( object, L0, L1 );
  2051.   if L20 >= 0 then                ! Yes, see if we can step 
  2052.     while object.x = L0 and object.y = L1 do
  2053.       ! Check for locked doors
  2054.       if object.type = DOOR and object.locktype > 0 then
  2055.         S0 = "The door is locked!";
  2056.         return;
  2057.       endif;
  2058.       ! Check for fences and things, both of which we should not
  2059.       ! be able to walk over.
  2060.       if object.type = FENCE or object.type = THING then
  2061.         s0 = swriteln("There is a ",object.name," in your way");
  2062.         return;
  2063.       endif;
  2064.       if object.index = 0 goto XDONE;
  2065.       dec( object.index );
  2066.       if failure goto XDONE;
  2067.     endwhile;
  2068.   endif;
  2069.  
  2070. :XDONE ! No blocking objects...
  2071.   !
  2072.   ! Now check the world's density and see if we can walk over it
  2073.   ! considering the type of landscape and the vehicle (or monster
  2074.   ! type) if any.
  2075.   !
  2076.   L20 = world.density(L0,L1);
  2077.   if L20 = WALL or L20 = LOCKED_DOOR or L20 = HIDDEN_DOOR then
  2078.     s0 = "You can't go there.";
  2079.     return;
  2080.   endif;
  2081.   on L21 goto
  2082.     CHK_WALK, CHK_MOUNT, CHK_ATV, CHK_LFLY, CHK_MFLY, CHK_HFLY, CHK_RAFT, CHK_BOAT;
  2083.   ! Anything else, don't allow the move !
  2084.   s0 = "You can't go there.";
  2085.   return;
  2086. ! -- ON WATER -- !
  2087. :CHK_RAFT
  2088.   if L20 = LOW_WATER or L20 = ROUGH_WATER goto GO_AHEAD;
  2089.   if L20 = DEEP_WATER then
  2090.     s0 = "You can't go in deep water.";
  2091.   else
  2092.     s0 = "No swiming allowed here.";
  2093.   endif;
  2094.   return;
  2095. :CHK_BOAT
  2096.   if L20 = DEEP_WATER goto GO_AHEAD;
  2097.   if L20 = LOW_WATER or L20 = ROUGH_WATER then
  2098.     s0 = "The water is not deep enough.";
  2099.   else
  2100.     s0 = "You can't go there.";
  2101.   endif;
  2102.   return;
  2103. ! -- BY AIR -- !
  2104. :CHK_LFLY
  2105.   if L20 = DEEP_WATER then
  2106.     s0 = "You can't fly over deep water.";
  2107.     return;
  2108.   endif;
  2109.   ! Drop Through !
  2110. :CHK_MFLY
  2111.   if L20 = VERY_HIGH  then 
  2112.     s0 = "You can't fly high enough.";
  2113.     return;
  2114.   endif;
  2115.   ! Drop Through !
  2116. :CHK_HFLY
  2117.   goto GO_AHEAD;
  2118. ! -- ON FOOT -- !
  2119. :CHK_WALK
  2120.   if L20 = FLAT or L20 = DESERT or L20 = SWAMP goto GO_AHEAD;
  2121.   if L20 = ROUGH      and random(3) <> 0 or
  2122.      L20 = VERY_ROUGH and random(3)  = 0     goto GO_AHEAD;
  2123.   ! Anything else, don't allow the move !
  2124.   if L20 = ROUGH or L20 = VERY_ROUGH then
  2125.     S0 = "The terrain is very rough.";
  2126.   else
  2127.     S0 = "You can't go there.";
  2128.   endif;
  2129.   return;
  2130. :CHK_MOUNT
  2131.   if L20 = FLAT                          or
  2132.      L20 = ROUGH                         or
  2133.      L20 = VERY_ROUGH and random(3) <> 0 then ! 2 out of 3 ! 
  2134.     goto GO_AHEAD;
  2135.   endif;
  2136.   if L20 = VERY_ROUGH then
  2137.     S0 = "The terrain is very rough.";
  2138.   endif;
  2139.   return;
  2140. :CHK_ATV
  2141.   if L20 = FLAT or L20 = ROUGH or L20 = VERY_ROUGH or L20 = LOW_WATER then
  2142.     goto GO_AHEAD; ! All Terrain Vehicle !
  2143.   endif;
  2144.   ! Anything else, don't allow the move !
  2145.   S0 = "You can't go there.";
  2146.   return;
  2147.  
  2148. :GO_AHEAD
  2149.   ! Go Ahead and Move
  2150.   L2 = YES;
  2151.   return;
  2152.  
  2153. :CHECK_GUARD
  2154.   !
  2155.   ! From GUARD.SCR, npc.v1 = 1 means you have given the password to the
  2156.   ! guard, so you can pass.  npc.v1 = 2 means you have given a BRIBE to
  2157.   ! the guard, so you can also pass.
  2158.   !
  2159.   if npc.type = GUARD and npc.v1 = 0 then
  2160.     s0 = "There is a GUARD there!";
  2161.     L2 = NO; ! Can't Pass !
  2162.   endif;
  2163.   return;
  2164.  
  2165.  
  2166.